let THREE=require('three');
import ColliderDetection from '../broad-component/collider-detection';
import CONST from '../collision-const';

const BOUND_CENTER=new THREE.Vector3(0,0,0);

/**
 * 碰撞体基类
 */
export default class Collider extends THREE.Object3D{
    constructor(values={}){
        super();
        this._values=values;
        this._init();
    }

    //-------------------------------------对外属性及方法--------------------------------------------

    /**
     * 获取类型
     * @returns {string}
     */
    get colliderType(){
        return CONST.COLLIDER_TYPE;
    }

    /**
     * 碰撞体是否启用
     * @returns {*|boolean}
     */
    get enabled(){
        return this._enabled;
    }

    /**
     * 启用或禁用碰撞体
     * @param bol
     */
    set enabled(bol){
        this._enabled=bol;
    }

    /**
     *获取包围盒（世界空间）
     */
    get bounds(){
        return new THREE.Box3();
    }

    /**
     * 碰撞体附加到的刚体
     * @returns {any}
     */
    get attachedRigidBody(){
        let rigid=this.userData.rigid;
        return rigid?rigid:null;
    }

    /**
     * 碰撞体附加到的物体
     * @returns {null}
     */
    get attachedObject(){
        let rigid=this.attachedRigidBody;
        return rigid?rigid.object:null;
    }

    /**
     * 开启或关闭调试
     * @param bol
     */
    set debug(bol){
        if(bol){
            if(this._debug)return;
            this._createDebug();
        }else{
            if(!this._debug)return;
            this._destroyDebug();
        }
    }

    /**
     * 获取包围盒（局部空间）
     * @returns {Box3}
     */
    get box(){
        return new THREE.Box3();
    }

    /**
     * 获取包围球（局部空间）
     * @returns {Sphere}
     */
    get sphere(){
        return new THREE.Sphere();
    }

    /**
     * 设置碰撞对象列表发生改变时的回调
     * 注意：
     *      列表对象发生改变时碰撞状态不一定会改变，例如一形状与2个形状发生碰撞，
     *      当其中一个退出碰撞后，此形状的碰撞状态并没有改变，但碰撞列表却改变了
     * @param func_add_remove {function}
     */
    set onContactChange(func_add_remove){
        this._onContactChange=func_add_remove;
    }

    /**
     * 设置碰撞进入时的回调
     * @param func
     */
    set onContactEnter(func){
        this._onContactEnter=func;
    }

    /**
     * 设置碰撞中时的回调
     * @param func
     */
    set onContactStay(func){
        this._onContactStay=func;
    }

    /**
     * 设置碰撞退出时的回调
     * @param func
     */
    set onContactExit(func){
        this._onContactExit=func;
    }

    /**
     * 获取碰撞状态
     * @returns {*|string}
     */
    get contactState(){
        return this._contactState;
    }

    /**
     * 获取中心点（世界空间）
     * @returns {Vector3}
     */
    get center(){
        return new THREE.Vector3().copy(BOUND_CENTER).applyMatrix4(this.matrixWorld);
    }

    /**
     * 获取颜色
     * @returns {*|Color}
     */
    get color(){
        return this._props.color;
    }

    /**
     * 设置颜色
     * @param color
     */
    set color(color){
        let c=this._props.color;
        if(color.r===c.r&&color.g===c.g&&color.b===c.b)return;
        this._props.color.copy(color);
        if(this._debug)this._debug.material.color=this._props.color;
    }

    /**
     * 射线检测函数（用户不建议使用）
     * @returns {null}
     */
    get raycast(){
        if(!this._enabled){
            return ()=>{};
        }
        return this._raycast;
    }

    /**
     * 检测与目标是否碰撞
     * @param collider
     * @param pointOnThis
     * @param pointOnThat
     * @returns {boolean|*}
     */
    check(collider,pointOnThis,pointOnThat){
        if(!this._enabled)return false;
        return ColliderDetection.checkColliderPair(this,collider,pointOnThis,pointOnThat);
    }

    /**
     * 设置碰撞状态（此为碰撞检测调用的函数，用户不建议使用）
     * @param contactState
     */
    set contactState(contactState){
        if(contactState===CONST.CONTACT_STATE_ENTER){
            this._dispatchContactEnterEvent();
            if(this._onContactEnter!==null)this._onContactEnter();
        }else if(contactState===CONST.CONTACT_STATE_STAY){
            this._dispatchContactStayEvent();
            if(this._onContactStay!==null)this._onContactStay();
        }else if(contactState===CONST.CONTACT_STATE_EXIT){
            this._dispatchContactExitEvent();
            if(this._onContactExit!==null)this._onContactExit();
        }else{
            console.warn('wrong type of contact state!');
            return;
        }
        this._contactState=contactState;
    }

    /**
     * 获取碰撞信息
     * @param collider
     * @returns {*}
     */
    getContactInfo(collider){
        for(let i=0;i<this._newContacts.length;i++){
            if(!this._newContacts[i])break;
            if(this._newContacts[i].uuid===collider.uuid){
                return this._contactInfo[i];
            }
        }
    }

    /**
     * 添加碰撞形状（此为碰撞检测调用的函数，用户不建议使用）
     * @param collider
     * @param point
     */
    addContact(collider,point){
        if(!this._enabled)return;
        for(let i=0;i<this._newContacts.length;i++){
            if(!this._newContacts[i]){
                this._newContacts[i]=collider;
                if(this._contactInfo[i]){
                    this._contactInfo[i].point.copy(point);
                }else{
                    this._contactInfo[i]={
                        point:new THREE.Vector3().copy(point),
                    };
                }
                this._newContacts[i+1]=null;
                break;
            }
            if(this._newContacts[i].uuid===collider.uuid)break;
        }
    }

    /**
     * 重置碰撞列表（此为碰撞检测调用的函数，用户不建议使用）
     */
    resetContact(){
        if(this._enabled) {
            for (let i = 0; i < this._newContacts.length; i++) {
                if (!this._newContacts[i]) {
                    this._oldContacts[i] = null;
                    break;
                }
                this._oldContacts[i] = this._newContacts[i];
            }
        }else{
            this._oldContacts[0]=null;
        }
        this._newContacts[0]=null;
    }

    /**
     * 确认碰撞列表状态（此为碰撞检测调用的函数，用户不建议使用）
     */
    confirmContact(){
        if(!this._enabled)return;
        let add=[];
        let remove=[];
        for(let s of this._newContacts){
            if(!s)break;
            let has=false;
            for(let o of this._oldContacts){
                if(!o)break;
                if(s.uuid===o.uuid){
                    has=true;
                    break;
                }
            }
            if(!has)add.push(s);
        }
        for(let s of this._oldContacts){
            if(!s)break;
            let has=false;
            for(let n of this._newContacts){
                if(!n)break;
                if(s.uuid===n.uuid){
                    has=true;
                    break;
                }
            }
            if(!has)remove.push(s);
        }

        if(add.length>0||remove.length>0){
            this._dispatchContactListChangeEvent(add,remove);
            if(this._onContactChange)this._onContactChange(add,remove);
        }
    }

    /**
     * 销毁
     */
    dispose() {
        if (this._debug)this._destroyDebug();
        this._shape=null;
        this._values=null;
        this._contactState=null;
        this._onContactEnter=null;
        this._onContactStay=null;
        this._onContactExit=null;
        this._onContactChange=null;
        this._newContacts=null;
        this._oldContacts=null;
        this._contactEnterEvent=null;
        this._contactStayEvent=null;
        this._contactExitEvent=null;
        this._listChangeEvent=null;
        this._props=null;
    }

    //------------------------------------------私有属性及方法----------------------------------------------

    /**
     * 绘制调试
     * @private
     */
    _createDebug(){}

    /**
     * 销毁调试
     * @private
     */
    _destroyDebug(){}

    /**
     * 初始化
     * @private
     */
    _init(){
        this._initProps();
        this._initVariable();
        this._initComponents();
        this._initEventBind();
        this._initialize();
    }

    /**
     * 初始化属性
     * @private
     */
    _initProps(){
        this._props={
            color:this._values.color||new THREE.Color(1,0,0),
        };
    }

    /**
     * 初始化事件函数
     * @private
     */
    _initEventBind(){
        this._contactEnterEvent={type:CONST.EVENT_TYPE_CONTACT_STATE_ENTER,rigid:null};
        this._dispatchContactEnterEvent=()=>{
            if(!this._enabled)return;
            this._contactEnterEvent.rigid=this.userData.rigid;
            this.dispatchEvent(this._contactEnterEvent);
        };

        this._contactStayEvent={type:CONST.EVENT_TYPE_CONTACT_STATE_STAY,rigid:null};
        this._dispatchContactStayEvent=()=>{
            if(!this._enabled)return;
            this._contactStayEvent.rigid=this.userData.rigid;
            this.dispatchEvent(this._contactStayEvent);
        };

        this._contactExitEvent={type:CONST.EVENT_TYPE_CONTACT_STATE_EXIT,rigid:null};
        this._dispatchContactExitEvent=()=>{
            if(!this._enabled)return;
            this._contactExitEvent.rigid=this.userData.rigid;
            this.dispatchEvent(this._contactExitEvent);
        };

        this._listChangeEvent={type:CONST.EVENT_TYPE_CONTACT_LIST_CHANGE,add:null,remove:null};
        this._dispatchContactListChangeEvent=(add,remove)=>{
            if(!this._enabled)return;
            this._listChangeEvent.add=add;
            this._listChangeEvent.remove=remove;
            this.dispatchEvent(this._listChangeEvent);
        };
    }

    /**
     * 初始化变量
     * @private
     */
    _initVariable(){
        this._enabled=true;
        this._raycast=null;
        this._shape=null;
        this._debug=null;
        this._contactState=CONST.CONTACT_STATE_EXIT;
        this._onContactEnter=null;
        this._onContactStay=null;
        this._onContactExit=null;
        this._onContactChange=null;
        this._newContacts=[null];
        this._oldContacts=[null];
        this._contactEnterEvent=null;
        this._contactStayEvent=null;
        this._contactExitEvent=null;
        this._listChangeEvent=null;
        this._contactInfo=[];
    }

    /**
     * 初始化组件状态
     * @private
     */
    _initialize(){
    }

    /**
     * 初始化组件
     * @private
     */
    _initComponents(){
        this._initShape();
        this._initRaycast();
    }

    /**
     * 初始化形状
     * @private
     */
    _initShape(){}

    /**
     * 射线检测函数
     * @private
     */
    _initRaycast(){}
}